import * as ts from 'typescript';

import { transpileModule } from './transpile';

describe('parse events', () => {
  it('events', () => {
    const t = transpileModule(`
      @Component({tag: 'cmp-a'})
      export class CmpA {
        /**
         * Hello, this is an event
         * @foo bar
         */
        @Event() thingChanged: EventEmitter<string>;
      }
    `);

    expect(t.event).toEqual({
      name: 'thingChanged',
      method: 'thingChanged',
      bubbles: true,
      cancelable: true,
      composed: true,
      internal: false,
      complexType: {
        original: 'string',
        resolved: 'string',
        references: {},
      },
      docs: {
        text: 'Hello, this is an event',
        tags: [
          {
            name: 'foo',
            text: 'bar',
          },
        ],
      },
    });
  });

  it('different options', () => {
    const t = transpileModule(`
      @Component({tag: 'cmp-a'})
      export class CmpA {
        @Event({
          eventName: 'ionChange',
          bubbles: false,
          cancelable: false,
          composed: false,
        }) thingChanged: EventEmitter<void>;
      }
    `);
    expect(t.event).toEqual({
      name: 'ionChange',
      method: 'thingChanged',
      bubbles: false,
      cancelable: false,
      composed: false,
      internal: false,
      complexType: {
        original: 'void',
        resolved: `void`,
        references: {},
      },
      docs: {
        text: '',
        tags: [],
      },
    });
  });

  it('no type', () => {
    const t = transpileModule(`
      @Component({tag: 'cmp-a'})
      export class CmpA {
        /**
         * Hello, this is an event
         * @foo bar
         */
        @Event() thingChanged: EventEmitter;
      }
    `);
    expect(t.event.complexType).toEqual({
      original: 'any',
      resolved: 'any',
      references: {},
    });
  });

  it('alias type', () => {
    const t = transpileModule(`
      export type Mode = 'md' | 'ios';

      @Component({tag: 'cmp-a'})
      export class CmpA {
        /**
         * Hello, this is an event
         * @foo bar
         */
        @Event() thingChanged: EventEmitter<Mode>;
      }
    `);
    expect(t.event.complexType).toEqual({
      original: 'Mode',
      resolved: `"ios" | "md"`,
      references: {
        Mode: {
          id: 'module.tsx::Mode',
          location: 'local',
          path: 'module.tsx',
        },
      },
    });
  });

  it('should merge extended class events meta', async () => {
    const t = transpileModule(
      `
      @Component({tag: 'cmp-a'})
      class CmpA extends Parent {
        @Event({bubbles: true}) anEvent: EventEmitter<string>; 
      }
      class Parent extends GrandParent {
        @Event({bubbles: false}) anEvent: EventEmitter<string>; 
      }
      class GrandParent {
        @Event({bubbles: false}) anGrandParentEvent: EventEmitter<string>; 
      }
    `,
      undefined,
      undefined,
      [],
      [],
      [],
      { target: ts.ScriptTarget.ESNext },
    );

    expect(t.events).toEqual([
      {
        bubbles: false,
        cancelable: true,
        complexType: {
          original: 'string',
          references: {},
          resolved: 'string',
        },
        composed: true,
        docs: {
          tags: [],
          text: '',
        },
        internal: false,
        method: 'anGrandParentEvent',
        name: 'anGrandParentEvent',
      },
      {
        bubbles: true,
        cancelable: true,
        complexType: {
          original: 'string',
          references: {},
          resolved: 'string',
        },
        composed: true,
        docs: {
          tags: [],
          text: '',
        },
        internal: false,
        method: 'anEvent',
        name: 'anEvent',
      },
    ]);
  });

  describe('resolveVar', () => {
    it('should resolve const variable in @Event eventName', () => {
      const t = transpileModule(`
        import { Component, Event, resolveVar, EventEmitter } from '@stencil/core';
        
        const MY_EVENT = 'myEvent';
        
        @Component({tag: 'cmp-a'})
        export class CmpA {
          @Event({ eventName: resolveVar(MY_EVENT) })
          myEvent: EventEmitter<string>;
        }
      `);
      expect(t.event).toEqual({
        name: 'myEvent',
        method: 'myEvent',
        bubbles: true,
        cancelable: true,
        composed: true,
        internal: false,
        complexType: {
          original: 'string',
          resolved: 'string',
          references: {},
        },
        docs: {
          text: '',
          tags: [],
        },
      });
    });

    it('should resolve object property in @Event eventName', () => {
      const t = transpileModule(`
        import { Component, Event, resolveVar, EventEmitter } from '@stencil/core';
        
        const EVENTS = {
          MY_EVENT: 'myEvent',
          OTHER_EVENT: 'otherEvent'
        } as const;
        
        @Component({tag: 'cmp-a'})
        export class CmpA {
          @Event({ eventName: resolveVar(EVENTS.MY_EVENT) })
          myEvent: EventEmitter<string>;
        }
      `);
      expect(t.event).toEqual({
        name: 'myEvent',
        method: 'myEvent',
        bubbles: true,
        cancelable: true,
        composed: true,
        internal: false,
        complexType: {
          original: 'string',
          resolved: 'string',
          references: {},
        },
        docs: {
          text: '',
          tags: [],
        },
      });
    });
  });
});
